// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.linqingying.gitcode.authentication.accounts


import com.google.common.cache.CacheBuilder
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.platform.util.coroutines.childScope
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.linqingying.gitcode.api.GitCodeApiRequestExecutor
import com.linqingying.gitcode.api.GitCodeApiRequests
import com.linqingying.gitcode.api.data.GitCodeAuthenticatedUser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.io.IOException
import java.time.Duration
import java.time.temporal.ChronoUnit

/**
 * Loads the account information or provides it from cache
 * TODO: more abstraction
 */
@Service(Service.Level.APP)
class GitCodeAccountInformationProvider(cs: CoroutineScope) : Disposable {

    private val informationCache = CacheBuilder.newBuilder()
        .expireAfterWrite(Duration.of(30, ChronoUnit.MINUTES))
        .build<GitCodeAccount, GitCodeAuthenticatedUser>()

    init {
        cs.childScope().launch {
            service<GCAccountManager>().accountsState.collect {
                informationCache.invalidateAll()
            }
        }
    }

    @RequiresBackgroundThread
    @Throws(IOException::class)
    fun getInformation(
        executor: GitCodeApiRequestExecutor,
        indicator: ProgressIndicator,
        account: GitCodeAccount
    ): GitCodeAuthenticatedUser {
        return informationCache.get(account) {
            executor.execute(
                indicator,
                GitCodeApiRequests.CurrentUser.get(account.server)
            )
        }
    }

    companion object {
        @JvmStatic
        fun getInstance(): GitCodeAccountInformationProvider {
            return service()
        }
    }

    override fun dispose() {
        informationCache.invalidateAll()
    }
}
